// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0

// cSpell: ignore resizer

global ResizeState {
    out property <length> handle-size: 8px;
}

component ResizeHandle inherits Rectangle {
    in property <bool> show-handle: true;
    in property <color> my-color: Colors.black;
    in property <MouseCursor> mouse-cursor;
    out property <bool> resizing <=> ta.pressed;

    callback resize(width: length, height: length, done: bool);
    callback resize-done(width: length, height: length);

    // Internal!
    in-out property <length> new-width;
    in-out property <length> new-height;
    in-out property <length> new-x;
    in-out property <length> new-y;

    width: ResizeState.handle-size;
    height: ResizeState.handle-size;

    background: root.show-handle ? Colors.white : Colors.transparent;
    border-color: root.show-handle ? root.my-color : Colors.transparent;

    border-width: 1px;

    ta := TouchArea {
        private property <length> x-offset: self.mouse-x - self.pressed-x;
        private property <length> y-offset: self.mouse-y - self.pressed-y;

        mouse-cursor <=> root.mouse-cursor;

        moved() => {
            root.resize(x-offset, y-offset, false);
        }
    }
}

export component Resizer {
    in property <length> x-position;
    in property <length> y-position;

    in property <bool> is-resizable: true;
    in property <bool> is-moveable: false;
    in property <color> color: Colors.black;
    in property <color> fill-color: Colors.white;
    out property <bool> resizing: n.resizing || ne.resizing || e.resizing || se.resizing || s.resizing || sw.resizing || w.resizing || nw.resizing;
    out property <bool> moving: resize-area.moving;
    out property <length> handle-size: ResizeState.handle-size;
    out property <bool> has-hover <=> ta.has-hover;

    callback resize(x: length, y: length, width: length, height: length, done: bool);
    callback can-move-to(x: length, y: length, mouse_x: length, mouse_y: length) -> bool;
    callback move-to(x: length, y: length, mouse_x: length, mouse_y: length);
    callback clicked(x: length, y: length, modifiers: KeyboardModifiers);
    callback double-clicked(x: length, y: length, modifiers: KeyboardModifiers);
    callback pointer-event(x: length, y: length, event: PointerEvent);
    callback scroll-event(event: PointerScrollEvent) -> EventResult;

    // Private!
    in-out property <length> top: self.y-position;
    in-out property <length> bottom: self.y-position + self.height;
    in-out property <length> left: self.x-position;
    in-out property <length> right: self.x-position + self.width;

    resize-area := Rectangle {
        in-out property <bool> moving: false;

        width <=> root.width;
        height <=> root.height;

        @children

        ta := TouchArea {
            enabled: root.is-moveable;

            private property <length> x-offset: self.mouse-x - self.pressed-x;
            private property <length> y-offset: self.mouse-y - self.pressed-y;
            private property <KeyboardModifiers> modifiers;
            private property <bool> has-moved: false;
            private property <bool> process-moves: false;
            private property <bool> can-move-to: false;

            mouse-cursor: MouseCursor.move;

            double-clicked() => {
                root.double-clicked(self.mouse-x, self.mouse-y, self.modifiers);
            }

            clicked() => {
                root.clicked(self.mouse-x, self.mouse-y, self.modifiers);
            }

            moved() => {
                if self.process-moves {
                    self.can-move-to = root.can-move-to(root.x-position + x-offset, root.y-position + y-offset, root.x-position + self.mouse-x, root.y-position + self.mouse-y);
                    self.has-moved = true;
                }
            }

            pointer-event(event) => {
                resize-area.moving = self.pressed;
                self.modifiers = event.modifiers;
                if event.button == PointerEventButton.left && event.kind == PointerEventKind.down {
                    self.process-moves = true;
                } else if self.has-moved && event.button == PointerEventButton.left && event.kind == PointerEventKind.up {
                    root.move-to(root.x-position + x-offset, root.y-position + y-offset, root.x-position + self.mouse-x, root.y-position + self.mouse-y);
                    self.has-moved = false;
                    self.process-moves = false;
                } else {
                    root.pointer-event(self.mouse-x, self.mouse-y, event);
                }
            }

            scroll-event(event) => {
                return root.scroll-event(event);
            }

            states [
                dragging-no-drop when self.has-moved && !self.can-move-to: {
                    mouse-cursor: MouseCursor.no-drop;
                }
                dragging-can-drop when self.has-moved && self.can-move-to: {
                    mouse-cursor: MouseCursor.copy;
                }
                normal when !self.has-moved: {
                    mouse-cursor: MouseCursor.default;
                }
            ]
        }
    }

    Rectangle {
        visible: is-resizable;

        n := ResizeHandle {
            show-handle: false;
            resize(x-offset, y-offset, done) => {
                self.new-width = root.width;
                self.new-height = Math.max(0px, y-offset * -1.0 + root.height);
                self.new-x = root.left;
                self.new-y = root.bottom - self.new-height;
                root.resize(self.new-x, self.new-y, self.new-width, self.new-height, done);
            }

            mouse-cursor: MouseCursor.n-resize;
            x: (root.handle-size / 2.0);
            y: -(root.handle-size / 2.0);
            width: root.width - root.handle-size;
        }

        ne := ResizeHandle {
            my-color: root.color;
            background: root.fill-color;
            resize(x-offset, y-offset, done) => {
                self.new-width = Math.max(0px, x-offset + root.width);
                self.new-height = Math.max(0px, y-offset * -1.0 + root.height);
                self.new-x = root.left;
                self.new-y = root.bottom - self.new-height;
                root.resize(self.new-x, self.new-y, self.new-width, self.new-height, done);
            }
            mouse-cursor: MouseCursor.ne-resize;
            x: root.width - (root.handle-size / 2.0);
            y: -(root.handle-size / 2.0);
        }

        e := ResizeHandle {
            show-handle: false;
            resize(x-offset, y-offset, done) => {
                self.new-width = Math.max(0px, x-offset + root.width);
                self.new-height = root.height;
                self.new-x = root.left;
                self.new-y = root.top;
                root.resize(self.new-x, self.new-y, self.new-width, self.new-height, done);
            }
            mouse-cursor: MouseCursor.e-resize;
            x: root.width - (root.handle-size / 2.0);
            y: root.handle-size / 2.0;
            height: root.height - root.handle-size;
        }

        se := ResizeHandle {
            my-color: root.color;
            background: root.fill-color;
            resize(x-offset, y-offset, done) => {
                self.new-width = Math.max(0px, x-offset + root.width);
                self.new-height = Math.max(0px, y-offset + root.height);
                self.new-x = root.left;
                self.new-y = root.top;
                root.resize(self.new-x, self.new-y, self.new-width, self.new-height, done);
            }
            mouse-cursor: MouseCursor.se-resize;
            x: root.width - (root.handle-size / 2.0);
            y: root.height - (root.handle-size / 2.0);
        }

        s := ResizeHandle {
            show-handle: false;
            resize(x-offset, y-offset, done) => {
                self.new-width = root.width;
                self.new-height = Math.max(0px, y-offset + root.height);
                self.new-x = root.left;
                self.new-y = root.top;
                root.resize(self.new-x, self.new-y, self.new-width, self.new-height, done);
            }
            mouse-cursor: MouseCursor.s-resize;
            x: root.handle-size / 2.0;
            y: root.height - (root.handle-size / 2.0);
            width: root.width - root.handle-size;
        }

        sw := ResizeHandle {
            my-color: root.color;
            background: root.fill-color;
            resize(x-offset, y-offset, done) => {
                self.new-width = Math.max(0px, x-offset * -1.0 + root.width);
                self.new-height = Math.max(0px, y-offset + root.height);
                self.new-x = root.right - self.new-width;
                self.new-y = root.top;
                root.resize(self.new-x, self.new-y, self.new-width, self.new-height, done);
            }
            mouse-cursor: MouseCursor.sw-resize;
            x: -(root.handle-size / 2.0);
            y: root.height - (root.handle-size / 2.0);
        }

        w := ResizeHandle {
            show-handle: false;
            resize(x-offset, y-offset, done) => {
                self.new-width = Math.max(0px, x-offset * -1.0 + root.width);
                self.new-height = root.height;
                self.new-x = root.right - self.new-width;
                self.new-y = root.top;
                root.resize(self.new-x, self.new-y, self.new-width, self.new-height, done);
            }
            mouse-cursor: MouseCursor.w-resize;
            x: -(root.handle-size / 2.0);
            y: (root.handle-size / 2.0);
            height: root.height - root.handle-size;
        }

        nw := ResizeHandle {
            my-color: root.color;
            background: root.fill-color;
            resize(x-offset, y-offset, done) => {
                self.new-width = Math.max(0px, x-offset * -1.0 + root.width);
                self.new-height = Math.max(0px, y-offset * -1.0 + root.height);
                self.new-x = root.right - self.new-width;
                self.new-y = root.bottom - self.new-height;
                root.resize(self.new-x, self.new-y, self.new-width, self.new-height, done);
            }
            mouse-cursor: MouseCursor.nw-resize;
            x: -(root.handle-size / 2.0);
            y: -(root.handle-size / 2.0);
        }
    }
}
